﻿Imports Automation.BDaq
Imports System.ComponentModel

Public Class PCIECard

    ''' <summary>
    ''' 得到符合名称规则的板卡索引
    ''' </summary>
    ''' <param name="name">板卡名称</param>
    ''' <returns>板卡索引</returns>
    ''' <remarks></remarks>
    Public Shared Function FindCard(name As String) As Integer
        Dim ret As Integer = -1
        Dim device_name As String = ""
        If DeviceCtrl.InstalledDevices.Count > 0 Then
            For i As Integer = 0 To DeviceCtrl.InstalledDevices.Count - 1
                device_name = DeviceCtrl.InstalledDevices.Item(i).ToString
                If device_name.Contains(name) Then
                    ret = DeviceCtrl.InstalledDevices.Item(i).DeviceNumber
                End If
            Next

            If ret < 0 Then
                Debug.Print("[ERROR] 没有找到板卡！")
            End If
        Else
            Debug.Print("[ERROR] 没有找到板卡！")
        End If

        Return ret

    End Function
End Class

Public Class AdDevice
    Public WithEvents card As WaveformAiCtrl
    Public buffAiData As Double() '所有通道的原始数据
    Public Channel As AdChannel()
    Public axisXData As Double() 'X坐标数据
    Public selectedChs As New List(Of Integer) '选中的通道，通道号必须连续
    Public axisXMax As Double '视窗长度
    Public Setting As AiSetting
    Public SampleCnt As UInteger
    Public Interval As Double '采样周期
    Public DataLength As UInteger
    Private Rate_ As Integer
    Private SectionLen_ As Integer

    <Description("通道0瞬时数值")>
    Property Instant0 As Double

    <Description("通道1瞬时数值")>
    Property Instant1 As Double

    ''' <summary>
    ''' 设备类
    ''' </summary>
    ''' <param name="index">板卡的引用</param>
    ''' <param name="max_channel">最大通道数</param>
    ''' <remarks></remarks>
    Public Sub New(index As Integer, Optional start_channel As Integer = 0, Optional max_channel As Integer = 2)
        Try
            card = New WaveformAiCtrl With {
                .SelectedDevice = New DeviceInformation(index)
            }
            ReDim Channel(max_channel - 1)
            Setting.brief = "Torque0"  '200Nm
            Setting.index = start_channel
            Setting.lineColor = Color.Black
            Setting.offset = 0
            Setting.ratio = 20
            Setting.lineWidth = 2
            Setting.max = 20
            Setting.min = -20

            Channel(0) = New AdChannel(Setting)
            Me.selectedChs.Add(Channel(0).index)

            Setting.brief = "Torque1"  '5000Nm
            Setting.index = start_channel + 1
            Setting.ratio = 500
            Setting.max = 2000
            Setting.min = -2000
            Setting.lineColor = Color.Red

            Channel(1) = New AdChannel(Setting)
            Me.selectedChs.Add(Channel(1).index)

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Critical)
        End Try
    End Sub

    <Description("设备已经准备好")>
    Property Ready As Boolean

    <Description("板卡状态")>
    ReadOnly Property State As ControlState
        Get
            Return card.State
        End Get
    End Property

    <Description("是否在处理数据中")>
    ReadOnly Property Busy As Boolean

    Private Sub UpdateAxisX()
        For i As Integer = 0 To DataLength - 1
            Me.axisXData(i) = SampleCnt * DataLength * Interval + i * Interval
        Next
    End Sub

    Private Sub DataReadyHandler(ByVal sender As Object, ByVal args As BfdAiEventArgs) Handles card.DataReady
        _Busy = True
        SampleCnt += 1
        If SampleCnt = 10000 Then SampleCnt = 0
        UpdateAxisX()
        Dim ret As ErrorCode
        ret = BufferAI.GetBufferData(card, Me.buffAiData)
        If ret = ErrorCode.Success Then
            GetChannelData(Channel(0))
            GetChannelData(Channel(1))
            Instant0 = Channel(0).buffer.Average()
            Instant1 = Channel(1).buffer.Average()
        End If
        _Busy = False
    End Sub

    ''' <summary>
    ''' 把通道数据从缓存中提取出来
    ''' </summary>
    ''' <param name="ch"></param>
    Private Sub GetChannelData(ch As AdChannel)
        BufferAI.GetChannelData(card, buffAiData, selectedChs.IndexOf(ch.index), ch.buffer, ratio:=ch.ratio, offset:=ch.offset)
    End Sub

    ''' <summary>
    ''' 修改变比，要在begin之前调用
    ''' </summary>
    ''' <param name="ratios">变比数组</param>
    Public Sub SetRatios(ratios() As Double)
        For i As Integer = 0 To 1
            Channel(i).ratio = ratios(i)
        Next
    End Sub

    ''' <summary>
    ''' 启动采样
    ''' </summary>
    ''' <param name="rate">采样率</param>
    ''' <param name="sectionLen">每个通道的采样数</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Begin(Optional rate As Integer = 10000, Optional sectionLen As Integer = 100) As Boolean
        Rate_ = rate
        SectionLen_ = sectionLen
        If card.State <> ControlState.Running Then
            SampleCnt = 0
            Interval = 1.0 / rate
            DataLength = sectionLen
            axisXMax = sectionLen * DataLength

            card.Conversion.ChannelCount = selectedChs.Count
            card.Conversion.ChannelStart = selectedChs(0)
            card.Conversion.ClockRate = rate
            card.Record.SectionCount = 0 '无限采样，直到手动结束
            card.Record.Cycles = 1
            card.Record.SectionLength = sectionLen
            For i As Integer = 0 To 7
                card.Channels(i).ValueRange = ValueRange.V_Neg10To10
            Next

            ReDim Me.axisXData(sectionLen - 1)

            '初始化x轴
            UpdateAxisX()

            If BufferAI.InitAi(card) = ErrorCode.Success Then
                _Ready = True
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    Public Sub [Stop]()
        card.Stop()
        SampleCnt = 0
    End Sub

    Public Sub Release()
        BufferAI.Release(card)
    End Sub

    Public Sub Restart()
        [Stop]()
        Release()
        Threading.Thread.Sleep(500)
        If Rate_ = 0 Then Rate_ = 50000
        If SectionLen_ = 0 Then SectionLen_ = 1000
        Begin(Rate_, SectionLen_)
        Debug.Print("Sensor Restarted.")
    End Sub

End Class

Public Structure AiSetting

    Public brief As String
    Public lineColor As Color
    Public lineWidth As Integer
    Public max As Double
    Public min As Double
    Public ratio As Double
    Public index As Integer
    '真实值为 (vi + offset) * ratio
    Public offset As Double

End Structure

Public Class AdChannel
    Public Shared lineColors As Color() = {Color.Red, Color.Black, Color.Blue, Color.Green, Color.Yellow, Color.Purple, Color.Pink, Color.SaddleBrown} '默认的曲线颜色

    Public buffer() As Double '数据缓存

    <DescriptionAttribute("曲线备注")>
    Public Property brief As String

    <DescriptionAttribute("曲线的颜色")>
    Public Property lineColor As Color

    <DescriptionAttribute("曲线粗细")>
    Public Property lineWidth As Integer

    <DescriptionAttribute("最大值")>
    Public Property max As Double

    <DescriptionAttribute("最小值")>
    Public Property min As Double

    <DescriptionAttribute("数据变比")>
    Public Property ratio As Double

    <DescriptionAttribute("通道编号")>
    Public Property index As Integer

    '真实值为 (vi + offset) * ratio
    <DescriptionAttribute("直流偏移量")>
    Public Property offset As Double

    Public Sub New(setting As AiSetting)
        lineColor = setting.lineColor
        index = setting.index
        max = setting.max
        min = setting.min
        lineWidth = setting.lineWidth
        ratio = setting.ratio
        offset = setting.offset
        brief = setting.brief
    End Sub

End Class

Public Class EventCounter

    Public Shared ReadOnly Counter As New EventCounterCtrl()
    Private Shared Ready As Boolean = False

    Public Shared Sub InitCounter(ch_cnt As Integer, ByRef device As DeviceInformation)
        If Not Ready Then
            Try
                Counter.SelectedDevice = device
                Counter.ChannelStart = 0
                Counter.ChannelCount = ch_cnt
                Ready = True
            Catch ex As Exception
                Debug.Print(ex.Message)
            End Try
        Else
            Debug.Print("[WARN] Already Started.")
        End If
    End Sub

    ''' <summary>
    ''' 初始化计数器
    ''' </summary>
    ''' <param name="ch_cnt">计数器数量</param>
    ''' <remarks></remarks>
    Public Shared Sub InitCounter(ch_cnt As Integer)
        InitCounter(ch_cnt, New DeviceInformation(PCIECard.FindCard("1812")))
    End Sub

    Public Shared Sub Start()
        If Ready Then
            Counter.Enabled = True
        End If
    End Sub

    Public Shared Sub [Stop]()
        Counter.Enabled = False
    End Sub

    Public Shared Function GetCount(Index As Integer) As Long
        Dim data(Counter.ChannelCount - 1) As Integer
        If Ready Then
            Counter.Read(Counter.ChannelCount, data)
        End If
        Return data(Index)
    End Function

End Class

Public Class UdConter

    Public Shared ReadOnly Counter As New UdCounterCtrl()
    Private Shared Ready As Boolean = False

    ''' <summary>
    ''' 初始化计数器
    ''' </summary>
    ''' <param name="ch_cnt">计数器数量</param>
    ''' <remarks></remarks>
    Public Shared Sub InitCounter(ch_cnt As Integer)
        If Not Ready Then
            Try
                Counter.SelectedDevice = New DeviceInformation(PCIECard.FindCard("1812"))
                Counter.ChannelStart = 0
                Counter.ChannelCount = ch_cnt
                Ready = True
            Catch ex As Exception
                Debug.Print(ex.Message)
            End Try
        Else
            Debug.Print("[WARN] Already Started.")
        End If
    End Sub

    Public Shared Sub SetCounterType(index As Integer, t As CountingType)
        Try
            Counter.Channels(index).CountingType = t
            Counter.Channels(index).InitialValue = 0
            Counter.Channels(index).NoiseFiltered = True
        Catch ex As Exception
            Debug.Print(ex.Message)
        End Try
    End Sub

    Public Shared Sub Start()
        Counter.Enabled = True
    End Sub

    Public Shared Sub [Stop]()
        Counter.Enabled = False
    End Sub

    Public Shared Sub Reset()
        Counter.ValueReset()
    End Sub

    Public Shared Function GetCount(index As Integer) As Integer
        Dim data(Counter.ChannelCount - 1) As Integer
        Counter.Read(Counter.ChannelCount, data)
        Return data(index)
    End Function

End Class
Public Class BufferAI

    ''' <summary>
    ''' 启动Ai板卡
    ''' </summary>
    ''' <param name="bufferAi">被启动的WaveformAiCtrl控件</param>
    ''' <returns>启动状态返回ErrorCode，成功则为ErrorCode.Success</returns>
    ''' <remarks></remarks>
    Public Shared Function InitAi(ByRef bufferAi As WaveformAiCtrl) As ErrorCode
        Dim ret As ErrorCode
        If bufferAi.Initialized Then
            ret = bufferAi.Prepare()
            If ret = ErrorCode.Success Then
                ret = bufferAi.Start()
                If ret = ErrorCode.Success Then
                    Debug.Print("Start Success.")
                    Return ret
                Else
                    Return ret
                    Debug.Print("Start Failed.")
                End If
            Else
                Debug.Print("Prepare Failed.")
                Return ret
            End If
        Else
            MsgBox("Initialize Failed.")
            '暂定这个ErrorCode
            Return ErrorCode.ErrorDeviceNotExist
        End If
    End Function

    ''' <summary>
    ''' 获取一组缓存数据
    ''' </summary>
    ''' <param name="bufferAi">WaveformAiCtril控件，采样率、数据长度等信息在这里设置</param>
    ''' <param name="refBuffer">采样的结果</param>
    ''' <returns>成功则为ErrorCode.Success</returns>
    ''' <remarks></remarks>
    Public Shared Function GetBufferData(ByRef bufferAi As WaveformAiCtrl, ByRef refBuffer As Double()) As ErrorCode
        Dim ret As ErrorCode = ErrorCode.ErrorDeviceNotExist
        Dim [return] As Integer
        If bufferAi.Initialized Then
            ReDim refBuffer(bufferAi.Record.SectionLength * bufferAi.Conversion.ChannelCount - 1)
            Try
                ret = bufferAi.GetData(bufferAi.Record.SectionLength * bufferAi.Conversion.ChannelCount, refBuffer, 200, [return])
            Catch sys_ex As AccessViolationException
                Debug.Print("[ERROR]: " + sys_ex.Message)
                bufferAi.Stop()
                bufferAi.Release()
                Debug.Print("Card STOP.")
            Catch ex As Exception
                Debug.Print(ex.Message)
            End Try
        Else
            Debug.Print("Device Not Initialized.")
        End If
        Return ret
    End Function

    ''' <summary>
    ''' 从连在一起的缓存数据区提取出每个通道的数据
    ''' 
    ''' </summary>
    ''' <param name="bufferAi">从那个waveform提取数据</param>
    ''' <param name="bufferData">连在一起的采样原始数据</param>
    ''' <param name="Channel">通道编号</param>
    ''' <param name="ChannelData">分离后存入的通道数据，经过变比换算</param>
    ''' <param name="ratio">数据变比，默认为1</param>
    ''' <param name="offset">直流偏移量，默认为0</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetChannelData(ByVal bufferAi As WaveformAiCtrl, ByVal bufferData As Double(), ByVal Channel As Integer, ByRef ChannelData As Double(), Optional ByVal ratio As Double = 1.0, Optional ByVal offset As Double = 0) As Boolean
        If bufferAi.Initialized Then
            If bufferData IsNot Nothing Then
                ReDim ChannelData(bufferAi.Record.SectionLength - 1)
                For i As Integer = 0 To UBound(ChannelData)
                    ChannelData(i) = (bufferData(Channel + i * bufferAi.Conversion.ChannelCount) + offset) * ratio
                Next
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    ''' <summary>
    ''' 释放控件资源
    ''' </summary>
    ''' <param name="bufferAi"></param>
    ''' <remarks></remarks>
    Public Shared Sub Release(ByRef bufferAi As WaveformAiCtrl)
        Try
            bufferAi.Release()
        Catch ex As Exception
            Debug.Print(ex.ToString)
        End Try
    End Sub

End Class

